home *** CD-ROM | disk | FTP | other *** search
/ Clickx 63 / Clickx 63.iso / software / multimedia / mirov204 / Miro_Installer.exe / xulrunner / chrome / toolkit.jar / content / global / nsDragAndDrop.js < prev    next >
Encoding:
JavaScript  |  2007-08-12  |  21.6 KB  |  613 lines

  1. //@line 39 "/e/xr19rel/WINNT_5.2_Depend/mozilla/toolkit/content/nsDragAndDrop.js"
  2.  
  3. /** 
  4.  *  nsTransferable - a wrapper for nsITransferable that simplifies
  5.  *                   javascript clipboard and drag&drop. for use in
  6.  *                   these situations you should use the nsClipboard
  7.  *                   and nsDragAndDrop wrappers for more convenience
  8.  **/ 
  9.  
  10. var nsTransferable = {
  11.   /**
  12.    * nsITransferable set (TransferData aTransferData) ;
  13.    *
  14.    * Creates a transferable with data for a list of supported types ("flavours")
  15.    * 
  16.    * @param TransferData aTransferData
  17.    *        a javascript object in the format described above 
  18.    **/ 
  19.   set: function (aTransferDataSet)
  20.     {
  21.       var trans = this.createTransferable();
  22.       for (var i = 0; i < aTransferDataSet.dataList.length; ++i) 
  23.         {
  24.           var currData = aTransferDataSet.dataList[i];
  25.           var currFlavour = currData.flavour.contentType;
  26.           trans.addDataFlavor(currFlavour);
  27.           var supports = null; // nsISupports data
  28.           var length = 0;
  29.           if (currData.flavour.dataIIDKey == "nsISupportsString")
  30.             {
  31.               supports = Components.classes["@mozilla.org/supports-string;1"]
  32.                                    .createInstance(Components.interfaces.nsISupportsString);
  33.  
  34.               supports.data = currData.supports;
  35.               length = supports.data.length;
  36.             }
  37.           else 
  38.             {
  39.               // non-string data.
  40.               supports = currData.supports;
  41.               length = 0; // kFlavorHasDataProvider
  42.             }
  43.           trans.setTransferData(currFlavour, supports, length * 2);
  44.         }
  45.       return trans;
  46.     },
  47.   
  48.   /**
  49.    * TransferData/TransferDataSet get (FlavourSet aFlavourSet, 
  50.    *                                   Function aRetrievalFunc, Boolean aAnyFlag) ;
  51.    *
  52.    * Retrieves data from the transferable provided in aRetrievalFunc, formatted
  53.    * for more convenient access.
  54.    *
  55.    * @param FlavourSet aFlavourSet
  56.    *        a FlavourSet object that contains a list of supported flavours.
  57.    * @param Function aRetrievalFunc
  58.    *        a reference to a function that returns a nsISupportsArray of nsITransferables
  59.    *        for each item from the specified source (clipboard/drag&drop etc)
  60.    * @param Boolean aAnyFlag
  61.    *        a flag specifying whether or not a specific flavour is requested. If false,
  62.    *        data of the type of the first flavour in the flavourlist parameter is returned,
  63.    *        otherwise the best flavour supported will be returned.
  64.    **/
  65.   get: function (aFlavourSet, aRetrievalFunc, aAnyFlag)
  66.     {
  67.       if (!aRetrievalFunc) 
  68.         throw "No data retrieval handler provided!";
  69.       
  70.       var supportsArray = aRetrievalFunc(aFlavourSet);
  71.       var dataArray = [];
  72.       var count = supportsArray.Count();
  73.       
  74.       // Iterate over the number of items returned from aRetrievalFunc. For
  75.       // clipboard operations, this is 1, for drag and drop (where multiple
  76.       // items may have been dragged) this could be >1.
  77.       for (var i = 0; i < count; i++)
  78.         {
  79.           var trans = supportsArray.GetElementAt(i);
  80.           if (!trans) continue;
  81.           trans = trans.QueryInterface(Components.interfaces.nsITransferable);
  82.             
  83.           var data = { };
  84.           var length = { };
  85.           
  86.           var currData = null;
  87.           if (aAnyFlag)
  88.             { 
  89.               var flavour = { };
  90.               trans.getAnyTransferData(flavour, data, length);
  91.               if (data && flavour)
  92.                 {
  93.                   var selectedFlavour = aFlavourSet.flavourTable[flavour.value];
  94.                   if (selectedFlavour) 
  95.                     dataArray[i] = FlavourToXfer(data.value, length.value, selectedFlavour);
  96.                 }
  97.             }
  98.           else
  99.             {
  100.               var firstFlavour = aFlavourSet.flavours[0];
  101.               trans.getTransferData(firstFlavour, data, length);
  102.               if (data && firstFlavour)
  103.                 dataArray[i] = FlavourToXfer(data.value, length.value, firstFlavour);
  104.             }
  105.         }
  106.       return new TransferDataSet(dataArray);
  107.     },
  108.  
  109.   /** 
  110.    * nsITransferable createTransferable (void) ;
  111.    *
  112.    * Creates and returns a transferable object.
  113.    **/    
  114.   createTransferable: function ()
  115.     {
  116.       const kXferableContractID = "@mozilla.org/widget/transferable;1";
  117.       const kXferableIID = Components.interfaces.nsITransferable;
  118.       return Components.classes[kXferableContractID].createInstance(kXferableIID);
  119.     }
  120. };  
  121.  
  122. /** 
  123.  * A FlavourSet is a simple type that represents a collection of Flavour objects.
  124.  * FlavourSet is constructed from an array of Flavours, and stores this list as
  125.  * an array and a hashtable. The rationale for the dual storage is as follows:
  126.  * 
  127.  * Array: Ordering is important when adding data flavours to a transferable. 
  128.  *        Flavours added first are deemed to be 'preferred' by the client. 
  129.  * Hash:  Convenient lookup of flavour data using the content type (MIME type)
  130.  *        of data as a key. 
  131.  */
  132. function FlavourSet(aFlavourList)
  133. {
  134.   this.flavours = aFlavourList || [];
  135.   this.flavourTable = { };
  136.  
  137.   this._XferID = "FlavourSet";
  138.   
  139.   for (var i = 0; i < this.flavours.length; ++i)
  140.     this.flavourTable[this.flavours[i].contentType] = this.flavours[i];
  141. }
  142.  
  143. FlavourSet.prototype = {
  144.   appendFlavour: function (aFlavour, aFlavourIIDKey)
  145.   {
  146.     var flavour = new Flavour (aFlavour, aFlavourIIDKey);
  147.     this.flavours.push(flavour);
  148.     this.flavourTable[flavour.contentType] = flavour;
  149.   }
  150. };
  151.  
  152. /** 
  153.  * A Flavour is a simple type that represents a data type that can be handled. 
  154.  * It takes a content type (MIME type) which is used when storing data on the
  155.  * system clipboard/drag and drop, and an IIDKey (string interface name
  156.  * which is used to QI data to an appropriate form. The default interface is
  157.  * assumed to be wide-string.
  158.  */ 
  159. function Flavour(aContentType, aDataIIDKey)
  160. {
  161.   this.contentType = aContentType;
  162.   this.dataIIDKey = aDataIIDKey || "nsISupportsString";
  163.  
  164.   this._XferID = "Flavour";
  165. }
  166.  
  167. function TransferDataBase() {}
  168. TransferDataBase.prototype = {
  169.   push: function (aItems)
  170.   {
  171.     this.dataList.push(aItems);
  172.   },
  173.  
  174.   get first ()
  175.   {
  176.     return "dataList" in this && this.dataList.length ? this.dataList[0] : null;
  177.   }
  178. };
  179.  
  180. /** 
  181.  * TransferDataSet is a list (array) of TransferData objects, which represents
  182.  * data dragged from one or more elements. 
  183.  */
  184. function TransferDataSet(aTransferDataList)
  185. {
  186.   this.dataList = aTransferDataList || [];
  187.  
  188.   this._XferID = "TransferDataSet";
  189. }
  190. TransferDataSet.prototype = TransferDataBase.prototype;
  191.  
  192. /** 
  193.  * TransferData is a list (array) of FlavourData for all the applicable content
  194.  * types associated with a drag from a single item. 
  195.  */
  196. function TransferData(aFlavourDataList)
  197. {
  198.   this.dataList = aFlavourDataList || [];
  199.  
  200.   this._XferID = "TransferData";
  201. }
  202. TransferData.prototype = {
  203.   __proto__: TransferDataBase.prototype,
  204.   
  205.   addDataForFlavour: function (aFlavourString, aData, aLength, aDataIIDKey)
  206.   {
  207.     this.dataList.push(new FlavourData(aData, aLength, 
  208.                        new Flavour(aFlavourString, aDataIIDKey)));
  209.   }
  210. };
  211.  
  212. /** 
  213.  * FlavourData is a type that represents data retrieved from the system 
  214.  * clipboard or drag and drop. It is constructed internally by the Transferable
  215.  * using the raw (nsISupports) data from the clipboard, the length of the data,
  216.  * and an object of type Flavour representing the type. Clients implementing
  217.  * IDragDropObserver receive an object of this type in their implementation of
  218.  * onDrop. They access the 'data' property to retrieve data, which is either data 
  219.  * QI'ed to a usable form, or unicode string. 
  220.  */
  221. function FlavourData(aData, aLength, aFlavour) 
  222. {
  223.   this.supports = aData;
  224.   this.contentLength = aLength;
  225.   this.flavour = aFlavour || null;
  226.   
  227.   this._XferID = "FlavourData";
  228. }
  229.  
  230. FlavourData.prototype = {
  231.   get data ()
  232.   {
  233.     if (this.flavour && 
  234.         this.flavour.dataIIDKey != "nsISupportsString" )
  235.       return this.supports.QueryInterface(Components.interfaces[this.flavour.dataIIDKey]); 
  236.     else {
  237.       var unicode = this.supports.QueryInterface(Components.interfaces.nsISupportsString);
  238.       if (unicode) 
  239.         return unicode.data.substring(0, this.contentLength/2);
  240.      
  241.       return this.supports;
  242.     }
  243.     return "";
  244.   }
  245. }
  246.  
  247. /** 
  248.  * Create a TransferData object with a single FlavourData entry. Used when 
  249.  * unwrapping data of a specific flavour from the drag service. 
  250.  */
  251. function FlavourToXfer(aData, aLength, aFlavour) 
  252. {
  253.   return new TransferData([new FlavourData(aData, aLength, aFlavour)]);
  254. }
  255.  
  256. var transferUtils = {
  257.  
  258.   retrieveURLFromData: function (aData, flavour)
  259.   {
  260.     switch (flavour) {
  261.       case "text/unicode":
  262.         return aData.replace(/^\s+|\s+$/g, "");
  263.       case "text/x-moz-url":
  264.         return aData.toString().split("\n")[0];
  265.       case "application/x-moz-file":
  266.         var ioService = Components.classes["@mozilla.org/network/io-service;1"]
  267.                                   .getService(Components.interfaces.nsIIOService);
  268.         var fileHandler = ioService.getProtocolHandler("file")
  269.                                    .QueryInterface(Components.interfaces.nsIFileProtocolHandler);
  270.         return fileHandler.getURLSpecFromFile(aData);
  271.     }
  272.     return null;                                                   
  273.   }
  274.  
  275. }
  276.  
  277. /**
  278.  * nsDragAndDrop - a convenience wrapper for nsTransferable, nsITransferable
  279.  *                 and nsIDragService/nsIDragSession. 
  280.  *
  281.  * Use: map the handler functions to the 'ondraggesture', 'ondragover' and
  282.  *   'ondragdrop' event handlers on your XML element, e.g.                   
  283.  *   <xmlelement ondraggesture="nsDragAndDrop.startDrag(event, observer);"   
  284.  *               ondragover="nsDragAndDrop.dragOver(event, observer);"      
  285.  *               ondragdrop="nsDragAndDrop.drop(event, observer);"/>         
  286.  *                                                                           
  287.  *   You need to create an observer js object with the following member      
  288.  *   functions:                                                              
  289.  *     Object onDragStart (event)        // called when drag initiated,      
  290.  *                                       // returns flavour list with data   
  291.  *                                       // to stuff into transferable      
  292.  *     void onDragOver (Object flavour)  // called when element is dragged   
  293.  *                                       // over, so that it can perform     
  294.  *                                       // any drag-over feedback for provided
  295.  *                                       // flavour                          
  296.  *     void onDrop (Object data)         // formatted data object dropped.   
  297.  *     Object getSupportedFlavours ()    // returns a flavour list so that   
  298.  *                                       // nsTransferable can determine
  299.  *                                       // whether or not to accept drop. 
  300.  **/   
  301.  
  302. var nsDragAndDrop = {
  303.   
  304.   _mDS: null,
  305.   get mDragService()
  306.     {
  307.       if (!this._mDS) 
  308.         {
  309.           const kDSContractID = "@mozilla.org/widget/dragservice;1";
  310.           const kDSIID = Components.interfaces.nsIDragService;
  311.           this._mDS = Components.classes[kDSContractID].getService(kDSIID);
  312.         }
  313.       return this._mDS;
  314.     },
  315.  
  316.   /**
  317.    * void startDrag (DOMEvent aEvent, Object aDragDropObserver) ;
  318.    *
  319.    * called when a drag on an element is started.
  320.    *
  321.    * @param DOMEvent aEvent
  322.    *        the DOM event fired by the drag init
  323.    * @param Object aDragDropObserver
  324.    *        javascript object of format described above that specifies
  325.    *        the way in which the element responds to drag events.
  326.    **/  
  327.   startDrag: function (aEvent, aDragDropObserver)
  328.     {
  329.       if (!("onDragStart" in aDragDropObserver))
  330.         return;
  331.  
  332.       const kDSIID = Components.interfaces.nsIDragService;
  333.       var dragAction = { action: kDSIID.DRAGDROP_ACTION_COPY + kDSIID.DRAGDROP_ACTION_MOVE + kDSIID.DRAGDROP_ACTION_LINK };
  334.  
  335.       var transferData = { data: null };
  336.       try 
  337.         {
  338.           aDragDropObserver.onDragStart(aEvent, transferData, dragAction);
  339.         }
  340.       catch (e) 
  341.         {
  342.           return;  // not a draggable item, bail!
  343.         }
  344.  
  345.       if (!transferData.data) return;
  346.       transferData = transferData.data;
  347.       
  348.       var transArray = Components.classes["@mozilla.org/supports-array;1"]
  349.                                  .createInstance(Components.interfaces.nsISupportsArray);
  350.  
  351.       var region = null;
  352.       if (aEvent.originalTarget.localName == "treechildren") {
  353.         // let's build the drag region
  354.         var tree = aEvent.originalTarget.parentNode;
  355.         try {
  356.           region = Components.classes["@mozilla.org/gfx/region;1"].createInstance(Components.interfaces.nsIScriptableRegion);
  357.           region.init();
  358.           var obo = tree.treeBoxObject;
  359.           var bo = obo.treeBody.boxObject;
  360.           var sel= obo.view.selection;
  361.  
  362.           var rowX = bo.x;
  363.           var rowY = bo.y;
  364.           var rowHeight = obo.rowHeight;
  365.           var rowWidth = bo.width;
  366.  
  367.           //add a rectangle for each visible selected row
  368.           for (var i = obo.getFirstVisibleRow(); i <= obo.getLastVisibleRow(); i ++)
  369.           {
  370.             if (sel.isSelected(i))
  371.               region.unionRect(rowX, rowY, rowWidth, rowHeight);
  372.             rowY = rowY + rowHeight;
  373.           }
  374.       
  375.           //and finally, clip the result to be sure we don't spill over...
  376.           region.intersectRect(bo.x, bo.y, bo.width, bo.height);
  377.         } catch(ex) {
  378.           dump("Error while building selection region: " + ex + "\n");
  379.           region = null;
  380.         }
  381.       }
  382.  
  383.       var count = 0;
  384.       do 
  385.         {
  386.           var trans = nsTransferable.set(transferData._XferID == "TransferData" 
  387.                                          ? transferData 
  388.                                          : transferData.dataList[count++]);
  389.           transArray.AppendElement(trans.QueryInterface(Components.interfaces.nsISupports));
  390.         }
  391.       while (transferData._XferID == "TransferDataSet" && 
  392.              count < transferData.dataList.length);
  393.       
  394.       try {
  395.         this.mDragService.invokeDragSessionWithImage(aEvent.target, transArray,
  396.                                                      region, dragAction.action,
  397.                                                      null, 0, 0, aEvent);
  398.       }
  399.       catch(ex) {
  400.         // this could be because the user pressed escape to
  401.         // cancel the drag. even if it's not, there's not much
  402.         // we can do, so be silent.
  403.       }
  404.       aEvent.stopPropagation();
  405.     },
  406.  
  407.   /** 
  408.    * void dragOver (DOMEvent aEvent, Object aDragDropObserver) ;
  409.    *
  410.    * called when a drag passes over this element
  411.    *
  412.    * @param DOMEvent aEvent
  413.    *        the DOM event fired by passing over the element
  414.    * @param Object aDragDropObserver
  415.    *        javascript object of format described above that specifies
  416.    *        the way in which the element responds to drag events.
  417.    **/
  418.   dragOver: function (aEvent, aDragDropObserver)
  419.     { 
  420.       if (!("onDragOver" in aDragDropObserver)) 
  421.         return;
  422.       if (!this.checkCanDrop(aEvent, aDragDropObserver))
  423.         return;
  424.       var flavourSet = aDragDropObserver.getSupportedFlavours();
  425.       for (var flavour in flavourSet.flavourTable)
  426.         {
  427.           if (this.mDragSession.isDataFlavorSupported(flavour))
  428.             {
  429.               aDragDropObserver.onDragOver(aEvent, 
  430.                                            flavourSet.flavourTable[flavour], 
  431.                                            this.mDragSession);
  432.               aEvent.stopPropagation();
  433.               break;
  434.             }
  435.         }
  436.     },
  437.  
  438.   mDragSession: null,
  439.  
  440.   /** 
  441.    * void drop (DOMEvent aEvent, Object aDragDropObserver) ;
  442.    *
  443.    * called when the user drops on the element
  444.    *
  445.    * @param DOMEvent aEvent
  446.    *        the DOM event fired by the drop
  447.    * @param Object aDragDropObserver
  448.    *        javascript object of format described above that specifies
  449.    *        the way in which the element responds to drag events.
  450.    **/
  451.   drop: function (aEvent, aDragDropObserver)
  452.     {
  453.       if (!("onDrop" in aDragDropObserver))
  454.         return;
  455.       if (!this.checkCanDrop(aEvent, aDragDropObserver))
  456.         return;  
  457.       if (this.mDragSession.canDrop) {
  458.         var flavourSet = aDragDropObserver.getSupportedFlavours();
  459.         var transferData = nsTransferable.get(flavourSet, this.getDragData, true);
  460.         // hand over to the client to respond to dropped data
  461.         var multiple = "canHandleMultipleItems" in aDragDropObserver && aDragDropObserver.canHandleMultipleItems;
  462.         var dropData = multiple ? transferData : transferData.first.first;
  463.         aDragDropObserver.onDrop(aEvent, dropData, this.mDragSession);
  464.       }
  465.       aEvent.stopPropagation();
  466.     },
  467.  
  468.   /** 
  469.    * void dragExit (DOMEvent aEvent, Object aDragDropObserver) ;
  470.    *
  471.    * called when a drag leaves this element
  472.    *
  473.    * @param DOMEvent aEvent
  474.    *        the DOM event fired by leaving the element
  475.    * @param Object aDragDropObserver
  476.    *        javascript object of format described above that specifies
  477.    *        the way in which the element responds to drag events.
  478.    **/
  479.   dragExit: function (aEvent, aDragDropObserver)
  480.     {
  481.       if (!this.checkCanDrop(aEvent, aDragDropObserver))
  482.         return;
  483.       if ("onDragExit" in aDragDropObserver)
  484.         aDragDropObserver.onDragExit(aEvent, this.mDragSession);
  485.     },  
  486.     
  487.   /** 
  488.    * void dragEnter (DOMEvent aEvent, Object aDragDropObserver) ;
  489.    *
  490.    * called when a drag enters in this element
  491.    *
  492.    * @param DOMEvent aEvent
  493.    *        the DOM event fired by entering in the element
  494.    * @param Object aDragDropObserver
  495.    *        javascript object of format described above that specifies
  496.    *        the way in which the element responds to drag events.
  497.    **/
  498.   dragEnter: function (aEvent, aDragDropObserver)
  499.     {
  500.       if (!this.checkCanDrop(aEvent, aDragDropObserver))
  501.         return;
  502.       if ("onDragEnter" in aDragDropObserver)
  503.         aDragDropObserver.onDragEnter(aEvent, this.mDragSession);
  504.     },  
  505.     
  506.   /** 
  507.    * nsISupportsArray getDragData (Object aFlavourList)
  508.    *
  509.    * Creates a nsISupportsArray of all droppable items for the given
  510.    * set of supported flavours.
  511.    * 
  512.    * @param FlavourSet aFlavourSet
  513.    *        formatted flavour list.
  514.    **/  
  515.   getDragData: function (aFlavourSet)
  516.     {
  517.       var supportsArray = Components.classes["@mozilla.org/supports-array;1"]
  518.                                     .createInstance(Components.interfaces.nsISupportsArray);
  519.  
  520.       for (var i = 0; i < nsDragAndDrop.mDragSession.numDropItems; ++i)
  521.         {
  522.           var trans = nsTransferable.createTransferable();
  523.           for (var j = 0; j < aFlavourSet.flavours.length; ++j)
  524.             trans.addDataFlavor(aFlavourSet.flavours[j].contentType);
  525.           nsDragAndDrop.mDragSession.getData(trans, i);
  526.           supportsArray.AppendElement(trans);
  527.         }
  528.       return supportsArray;
  529.     },
  530.  
  531.   /** 
  532.    * Boolean checkCanDrop (DOMEvent aEvent, Object aDragDropObserver) ;
  533.    *
  534.    * Sets the canDrop attribute for the drag session.
  535.    * returns false if there is no current drag session.
  536.    *
  537.    * @param DOMEvent aEvent
  538.    *        the DOM event fired by the drop
  539.    * @param Object aDragDropObserver
  540.    *        javascript object of format described above that specifies
  541.    *        the way in which the element responds to drag events.
  542.    **/
  543.   checkCanDrop: function (aEvent, aDragDropObserver)
  544.     {
  545.       if (!this.mDragSession) 
  546.         this.mDragSession = this.mDragService.getCurrentSession();
  547.       if (!this.mDragSession) 
  548.         return false;
  549.       this.mDragSession.canDrop = this.mDragSession.sourceNode != aEvent.target;
  550.       if ("canDrop" in aDragDropObserver)
  551.         this.mDragSession.canDrop &= aDragDropObserver.canDrop(aEvent, this.mDragSession);
  552.       return true;
  553.     },
  554.  
  555.   /**
  556.    * Do a security check for drag n' drop. Make sure the source document
  557.    * can load the dragged link.
  558.    *
  559.    * @param DOMEvent aEvent
  560.    *        the DOM event fired by leaving the element
  561.    * @param Object aDragDropObserver
  562.    *        javascript object of format described above that specifies
  563.    *        the way in which the element responds to drag events.
  564.    * @param String aDraggedText
  565.    *        the text being dragged
  566.    **/
  567.   dragDropSecurityCheck: function (aEvent, aDragSession, aDraggedText)
  568.     {
  569.       var sourceDoc = aDragSession.sourceDocument;
  570.       if (!sourceDoc)
  571.         return;
  572.  
  573.       // Strip leading and trailing whitespace, then try to create a
  574.       // URI from the dropped string. If that succeeds, we're
  575.       // dropping a URI and we need to do a security check to make
  576.       // sure the source document can load the dropped URI. We don't
  577.       // so much care about creating the real URI here
  578.       // (i.e. encoding differences etc don't matter), we just want
  579.       // to know if aDraggedText really is a URI.
  580.  
  581.       aDraggedText = aDraggedText.replace(/^\s*|\s*$/g, '');
  582.  
  583.       var uri;
  584.  
  585.       try {
  586.         uri = Components.classes["@mozilla.org/network/io-service;1"]
  587.                         .getService(Components.interfaces.nsIIOService)
  588.                         .newURI(aDraggedText, null, null);
  589.       } catch (e) {
  590.       }
  591.  
  592.       if (!uri)
  593.         return;
  594.  
  595.       // aDraggedText is a URI, do the security check.
  596.       const nsIScriptSecurityManager = Components.interfaces
  597.                                                  .nsIScriptSecurityManager;
  598.       var secMan = Components.classes["@mozilla.org/scriptsecuritymanager;1"]
  599.                              .getService(nsIScriptSecurityManager);
  600.  
  601.       try {
  602.         secMan.checkLoadURIStr(sourceDoc.documentURI, aDraggedText,
  603.                                nsIScriptSecurityManager.STANDARD);
  604.       } catch (e) {
  605.         // Stop event propagation right here.
  606.         aEvent.stopPropagation();
  607.  
  608.         throw "Drop of " + aDraggedText + " denied.";
  609.       }
  610.     }
  611. };
  612.  
  613.